#include "processor.h"


void processing_element::writeback(unsigned int lane_number) {
	unsigned int index;

	// Check if there is an instruction in the Writeback Stage of the specified Execution Lane.
	if (Execution_Lanes[lane_number].wb.valid) {

		//////////////////////////////////////////////////////////////////////////////////////////////////////////
		// Get the instruction's index into PAY.
		//////////////////////////////////////////////////////////////////////////////////////////////////////////
		index = Execution_Lanes[lane_number].wb.index;

		//////////////////////////////////////////////////////////////////////////////////////////////////////////
		// FIX_ME #15
		// Resolve branches.
		//
		// Background: Here we are resolving a branch that previously made a checkpoint.
		//
		// If the branch was correctly predicted, then resolution consists of two steps:
		// * Tell each renamer module that the branch resolved correctly, so that it frees its corresponding checkpoint.
		// * Clear the branch's bit in the branch masks of instructions in the pipeline. Specifically, this
		//   involves instructions from the Rename Stage (where branch masks are first assigned) to the
		//   Writeback Stage (instructions leave the pipeline after Writeback, although they still hold
		//   entries in the Active List and Load/Store Queues).
		//
		// If the branch was mispredicted, then resolution consists of two high-level steps:
		// * Recover key units: the Fetch Unit, the renamer modules (RMTs, FLs, ALs), and the LSU.
		// * Squash instructions in the pipline that are logically after the branch -- those instructions
		//   that have the branch's bit in their branch masks -- meanwhile clearing that bit. Also, all
		//   instructions in the frontend stages are automatically squashed since they are by definition
		//   logically after the branch.
		//////////////////////////////////////////////////////////////////////////////////////////////////////////
		if (top_level->PAY.buf[index].checkpoint) {
			if (PERFECT_BRANCH_PRED) {
				if (!top_level->wait_for_trap)
					assert(top_level->PAY.buf[index].next_pc == top_level->PAY.buf[index].c_next_pc);

				// FIX_ME #15a
				// The simulator is running in perfect branch prediction mode, therefore, all branches are correctly predicted.
				// The assertion immediately above confirms that the prediction (next_pc is the predicted target)
				// matches the outcome (c_next_pc is the calculated target).
				//
				// Tips:
				// 1. At this point of the code, 'index' is the instruction's index into PAY.buf[] (payload).
				// 2. Call the resolve() function of both the integer and floating-point renamer modules so that they free
				//    the branch's checkpoint. Recall that the arguments to resolve() are:
				//    * Active List index
				//    * The branch's ID
				//    * Whether or not the branch was predicted correctly: in this case it is correct
				// 3. Do NOT worry about clearing the branch's bit in the branch masks of instructions in the pipeline.
				//    This is unnecessary since instructions don't need accurate branch masks in perfect branch prediction
				//    mode... since they are never squashed anyway.

				/*REN_INT->resolve(PAY.buf[index].AL_index_int, PAY.buf[index].branch_ID, true);
	    REN_FP->resolve(PAY.buf[index].AL_index_fp, PAY.buf[index].branch_ID, true);*/

			}
			else if (top_level->PAY.buf[index].next_pc == top_level->PAY.buf[index].c_next_pc) {
				// FIX_ME #15b
				// The simulator is running in real branch prediction mode, and the branch was correctly predicted.
				// You can see this in the comparison above: the prediction (next_pc is the predicted target)
				// matches the outcome (c_next_pc is the calculated target).
				//
				// Branch was predicted correctly.
				//
				// Tips:
				// 1. See #15a, item 1.
				// 2. See #15a, item 2.
				// 3. Clear the branch's bit in the branch masks of instructions in the pipeline.
				//    To do this, call the resolve() function with the appropriate arguments. This function does the work for you.
				//    * resolve() is a private function of the processor class, therefore, just call it literally as 'resolve'.
				//    * resolve() takes two arguments. The first argument is the branch's ID. The second argument is a flag that
				//      indicates whether or not the branch was predicted correctly: in this case it is correct.
				//    * See processor.h for details about the two arguments of resolve().

				/*REN_INT->resolve(PAY.buf[index].AL_index_int, PAY.buf[index].branch_ID, true);
		 REN_FP->resolve(PAY.buf[index].AL_index_fp, PAY.buf[index].branch_ID, true);*/


				//resolve(top_level->PAY.buf[index].branch_ID, true);

			}
			else {
				// Branch was mispredicted.

				// Roll-back the fetch unit: PC and branch predictor only if

				top_level->set_pc(top_level->TQ.get_starting_PC(my_ID));
				top_level->set_mispredict_param(top_level->PAY.buf[index].pc, top_level->PAY.buf[index].c_next_pc);

				//pc = top_level->PAY.buf[index].c_next_pc;					// PC gets the correct target of the resolved branch.
				top_level->BP.fix_pred(top_level->PAY.buf[index].pred_tag, top_level->PAY.buf[index].c_next_pc);	// Roll-back the branch predictor to the point of the resolved branch.

				// FIX_ME #15c
				// The simulator is running in real branch prediction mode, and the branch was mispredicted.
				// Recall the two high-level steps that are necessary in this case:
				// * Recover key units: the Fetch Unit, the renamer modules (RMTs, FLs, ALs), and the LSU.
				//   The Fetch Unit is recovered in the statements immediately preceding this comment (please study them for knowledge).
				//   The LSU is recovered in the statements immediately following this comment (please study them for knowledge).
				//   Your job for #15c will be to recover the renamer modules, in between.
				// * Squash instructions in the pipeline that are logically after the branch. You will do this too, in #15d below.
				//
				// Restore the RMT, FL, and AL.
				//
				// Tips:
				// 1. See #15a, item 1.
				// 2. See #15a, item 2 -- EXCEPT in this case the branch was mispredicted, so specify not-correct instead of correct.
				//    This will restore the RMT, FL, and AL, and also free this and future checkpoints... etc.

				top_level->REN_INT->resolve(top_level->PAY.buf[index].AL_index_int, top_level->PAY.buf[index].branch_ID, false);
				top_level->REN_FP->resolve(top_level->PAY.buf[index].AL_index_fp, top_level->PAY.buf[index].branch_ID, false);


				unsigned int s_index = top_level->TQ.get_pay_index(my_ID);
				// Restore the LQ/SQ.
				top_level->LSU.restore(top_level->PAY.buf[s_index].LQ_index, top_level->PAY.buf[s_index].LQ_phase, top_level->PAY.buf[s_index].SQ_index, top_level->PAY.buf[s_index].SQ_phase);

				// FIX_ME #15d
				// Squash instructions after the branch in program order, in all pipeline registers and the IQs.
				//
				// Tips:
				// 1. At this point of the code, 'index' is the instruction's index into PAY.buf[] (payload).
				// 2. Squash instructions after the branch in program order.
				//    To do this, call the resolve() function with the appropriate arguments. This function does the work for you.
				//    * resolve() is a private function of the processor class, therefore, just call it literally as 'resolve'.
				//    * resolve() takes two arguments. The first argument is the branch's ID. The second argument is a flag that
				//      indicates whether or not the branch was predicted correctly: in this case it is not-correct.
				//    * See processor.h for details about the two arguments of resolve().

				top_level->resolve(top_level->PAY.buf[index].branch_ID, false);

				// Rollback PAY to the point of the branch.
				top_level->PAY.rollback(s_index-2);	//this function rolls the payload index to index +2, but we want the starting PC to be executed again
				top_level->TQ.clear_valid(my_ID);	//clear valid bit for PE[ID]

				// In case this PE is last in FIFO, this can be freed
				if(top_level->TQ.free_if_last_PE(my_ID))
					set_free();
			}
		}

		//////////////////////////////////////////////////////////////////////////////////////////////////////////
		// FIX_ME #16
		// Set completed bits in Active Lists.
		//
		// Tips:
		// 1. At this point of the code, 'index' is the instruction's index into PAY.buf[] (payload).
		// 2. Set the completed bit for this instruction in both the integer Active List and floating-point Active List.
		//////////////////////////////////////////////////////////////////////////////////////////////////////////

		top_level->REN_INT->set_complete(top_level->PAY.buf[index].AL_index_int);
		top_level->REN_FP->set_complete(top_level->PAY.buf[index].AL_index_fp);

		top_level->TQ.inc_completed_inst(my_ID);
		//////////////////////////////////////////////////////////////////////////////////////////////////////////
		// Remove the instruction from the Execution Lane.
		//////////////////////////////////////////////////////////////////////////////////////////////////////////
		Execution_Lanes[lane_number].wb.valid = false;

	}
}
